package com.cmict.data.infra.service.message.sms;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.cmict.data.framework.common.enums.UserTypeEnum;
import com.cmict.data.framework.sms.core.client.SmsClient;
import com.cmict.data.framework.sms.core.client.SmsClientFactory;
import com.cmict.data.framework.sms.core.client.SmsCommonResult;
import com.cmict.data.framework.sms.core.client.dto.SmsReceiveRespDTO;
import com.cmict.data.framework.sms.core.client.dto.SmsSendRespDTO;
import com.cmict.data.infra.mq.message.sms.SmsSendMessage;
import com.cmict.data.system.api.user.AdminUserApi;
import com.cmict.data.system.api.user.dto.AdminUserRespDTO;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

import static com.cmict.data.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cmict.data.system.enums.ErrorCodeConstants.SMS_SEND_MOBILE_NOT_EXISTS;

/**
 * 短信发送 Service 发送的实现
 *
 * @author awesome
 */
@Service
public class SmsChannelSendServiceImpl implements SmsChannelSendService {

    @Resource
    private AdminUserApi adminUserApi;
//    @Resource
//    private MemberUserApi memberUserApi;


    @Resource
    private SmsClientFactory smsClientFactory;

//    @Resource
//    private SmsChannelProducer smsChannelProducer;

    @Override
    public Long sendSingleSmsToAdmin(String mobile, Long userId, String templateCode, Map<String, Object> templateParams) {
        // 如果 mobile 为空，则加载用户编号对应的手机号
        if (StrUtil.isEmpty(mobile)) {
            AdminUserRespDTO user = adminUserApi.getUser(userId).getCheckedData();
            if (user != null) {
                mobile = user.getMobile();
            }
        }
        // 执行发送
        return this.sendSingleSms(mobile, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
    }

//    @Override
//    public Long sendSingleSmsToMember(String mobile, Long userId, String templateCode, Map<String, Object> templateParams) {
//        // 如果 mobile 为空，则加载用户编号对应的手机号
//        if (StrUtil.isEmpty(mobile)) {
//            UserRespDTO user = memberUserApi.getUser(userId);
//            if (user != null) {
//                mobile = user.getMobile();
//            }
//        }
//        // 执行发送
//        return this.sendSingleSms(mobile, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
//    }

    @Override
    public Long sendSingleSms(String mobile, Long userId, Integer userType,
                              String templateCode, Map<String, Object> templateParams) {
//        // 校验短信模板是否合法
//        SmsTemplateDO template = this.checkSmsTemplateValid(templateCode);
//        // 校验手机号码是否存在
//        mobile = this.checkMobile(mobile);
//        // 构建有序的模板参数。为什么放在这个位置，是提前保证模板参数的正确性，而不是到了插入发送日志
//        List<KeyValue<String, Object>> newTemplateParams = this.buildTemplateParams(template, templateParams);
//
//        // 创建发送日志。如果模板被禁用，则不发送短信，只记录日志
//        Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
//        String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
//        Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams);
//
//        // 发送 MQ 消息，异步执行发送短信
//        if (isSend) {
//            smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(),
//                    template.getApiTemplateId(), newTemplateParams);
//        }
//        return sendLogId;
        return 1l;
    }


//    @VisibleForTesting
//    public SmsTemplateDO checkSmsTemplateValid(String templateCode) {
//        // 获得短信模板。考虑到效率，从缓存中获取
//        SmsTemplateDO template = smsTemplateService.getSmsTemplateByCodeFromCache(templateCode);
//        // 短信模板不存在
//        if (template == null) {
//            throw exception(SMS_SEND_TEMPLATE_NOT_EXISTS);
//        }
//        return template;
//    }

    /**
     * 将参数模板，处理成有序的 KeyValue 数组
     *
     * 原因是，部分短信平台并不是使用 key 作为参数，而是数组下标，例如说腾讯云 https://cloud.tencent.com/document/product/382/39023
     *
//     * @param template 短信模板
//     * @param templateParams 原始参数
     * @return 处理后的参数
     */
//    @VisibleForTesting
//    public List<KeyValue<String, Object>> buildTemplateParams(SmsTemplateDO template, Map<String, Object> templateParams) {
//        return template.getParams().stream().map(key -> {
//            Object value = templateParams.get(key);
//            if (value == null) {
//                throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, key);
//            }
//            return new KeyValue<>(key, value);
//        }).collect(Collectors.toList());
//    }

    @VisibleForTesting
    public String checkMobile(String mobile) {
        if (StrUtil.isEmpty(mobile)) {
            throw exception(SMS_SEND_MOBILE_NOT_EXISTS);
        }
        return mobile;
    }

    @Override
    public void doSendSms(SmsSendMessage message) {
        // 获得渠道对应的 SmsClient 客户端
        SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId());
        Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId()));
        // 发送短信
        SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(),
                message.getApiTemplateId(), message.getTemplateParams());

    }

    @Override
    public void receiveSmsStatus(String channelCode, String text) throws Throwable {
        // 获得渠道对应的 SmsClient 客户端
        SmsClient smsClient = smsClientFactory.getSmsClient(channelCode);
        Assert.notNull(smsClient, String.format("短信客户端(%s) 不存在", channelCode));
        // 解析内容
        List<SmsReceiveRespDTO> receiveResults = smsClient.parseSmsReceiveStatus(text);
        if (CollUtil.isEmpty(receiveResults)) {
            return;
        }
        // 更新短信日志的接收结果. 因为量一般不大，所以先使用 for 循环更新
//        receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(result.getLogId(),
//                result.getSuccess(), result.getReceiveTime(), result.getErrorCode(), result.getErrorCode()));
    }

}
